// Copyright (c) WanSheng Intelligent Corp. All rights reserved.
// Licensed under the LGPL v3.0 license. 


#ifndef __MODBUS_PLUGIN_H__
#define __MODBUS_PLUGIN_H__

#define LOG_TAG "MODBUS"
 
#include <stdlib.h>
#include <modbus.h>
#include <linux/prctl.h>
#include "path.h"
#include "ams_constants.h"

#include "plugin_constants.h"
#include "agent_core_lib.h"
#include "parson.h"
#include "er-coap.h"
#include "er-coap-constants.h"
#include "string_parser.h"
#include "logs.h"
#include "parson_ext.h"
#include "modbus_coding.h"
#include "cJSON_ext.h"
#include "wa_edge_types.h"
#include "wa_plugin_sdk.h"
#include "wa_bus.h"

#define PLUGIN_NAME "modbus_plugin"

#define FLAG_MODBUS_ACCESS  		0x00000001
#define FLAG_MODBUS_LOG				0x00000002
#define FLAG_RESOURCE_WRITE			0x00000004
#define FLAG_RESOURCE_READ			0x00000008
#define FLAG_RESOURCE_META			0x00000010



#define FLAG_MODBUS_SUCCESS 		0x10000000
#define FLAG_MODBUS_DATA			0x20000000
#define FLAG_PING					0x40000000
#define FLAG_BUS_AUTO_CLOSE			0x80000000
#define FLAG_DEBUG_URL				0x01000000
#define FLAG_VALUE_CONVERT          0x02000000
#define FLAG_MB_CMD_ERROR           0x04000000
#define FLAG_MB_CMD_MSG             0x08000000


#define MODBUS_LOG_DATA(title, buffer, len) if((log_tag_mask[Log2_Modbus] & FLAG_MODBUS_DATA) && (len > 0) && (LOG_VERBOSE   == log_level)) log_buffer(title,buffer, len)
#define NOT_DEFINED (-1)

#define ZS_TASK_CONNECT "BUS-CONNECT"

typedef struct i_modbus
{
	struct i_modbus * next;
	wa_bus_info_t * addr;
	modbus_t * bus_ctx;
	int quit;
	int min_wait_ms;
	int response_wait_ms;
	int current_slave_id;
    tick_time_t last_access;
    unsigned int fails;
    unsigned int total_fails;
	unsigned int drop_msgs;
	unsigned int overflow_msgs;
	int recent_errno;
	enum {
		S_Bus_Disconnected = 0,
		S_Bus_Connected,
        S_Bus_Closed    // closed the bus before next requst come
	}status;	// tcp disconnected: 0
}i_modbus_t;




typedef struct i_modbus_device
{
	struct i_modbus_device * next;
	char * id;
	char * device_type;
	int slave_id;
	i_modbus_t * bus;
	int fails;
	tick_time_t last_access;
	bool online;
}i_modbus_device_t;



typedef struct i_modbus_command
{
	int slave_id;
	int fc;
	int addr;
	int item_cnt;
    int fmt;
    int opaque;
	mb_coding_e coding;
	i_modbus_t * bus;
	char* data;
	int data_len;
}i_modbus_command_t;


extern i_modbus_t *g_modbus;
extern i_modbus_device_t * g_devices;
extern wa_plugin_device_info_t* g_devices_info;
extern int g_devices_info_size;

bool load_plugin_device_cfg();

void init_plugin();
void uninit_plugin();

const char * bus_name(i_modbus_t*  bus);

int exec_modbus_command(i_modbus_t * bus, int fc, int addr, int nb, char * in, char * out);

bool check_fc_read_write(int fc, bool yes_read);

// bus_executor.c
bool check_bus_connect(i_modbus_t * bus);


//Read_URL
char *read_command_from_modbus(i_modbus_command_t * cmd, int *fmt, int *payload_len);

//Write_URL
int write_command_to_modbus(i_modbus_command_t * cmd, int fmt);

bool is_coil_fc(int fc);
int fc_item_bytes(int fc);
int get_reg_type_fc(mb_reg_type_e rt, bool write);


//bus_devices.c
void add_device(i_modbus_device_t * device);
void add_modbus(i_modbus_t *modbus);
bool add_modbus_name(int bus_proto, char* bus_addr,int port,char* name);
i_modbus_device_t * find_mb_device(const char * name);
i_modbus_t * find_modbus_by_name(const char* name);
i_modbus_t * find_modbus_by_info(wa_bus_info_t * info);
int task_bus_connect(wa_task_t t);

bool retry_modbus_connect(i_modbus_t*  bus);
void disconnet_modbus(i_modbus_t*  bus);
void set_modbus_connection_status(i_modbus_t*  bus, int status);
void check_disconnect_bus(i_modbus_t *bus);


#endif /* APPS_IAGENT_CORE_SRC_MODBUS_MASTER_MODBUS_SERVER_H_ */
